// 模板方法模式由两部分结构组成，第一部分是抽象父类，第二部分是具体的实现子类。
// 通常在抽象父类中封装了子类的算法框架，包括实现一些公共方法和封装子类中所有方法的执行顺序。
// 子类通过继承这个抽象类，也继承了整个算法结构，并且可以选择重写父类的方法。


// 泡饮料的公共父类
let Beverage =  function(){};

Beverage.prototype.boilWater = function(){
    console.log("把水烧开")
}

// 冲泡
Beverage.prototype.brew = function(){}    // 空方法, 应该由子类重写
// 倒进杯子
Beverage.prototype.pourInCup = function(){} // 空方法, 应该由子类重写
// 
Beverage.prototype.addCondiments = function(){} //加调料, 由子类重写

Beverage.prototype.init = function(){
    this.boilWater();
    this.brew();
    this.pourInCup();
    this.addCondiments();
}

// 创建Coffee 和Tea子类
let Coffee = function(){}

Coffee.prototype = new Beverage();
// 接下来要重写抽象父类中的一些方法，只有“把水煮沸”这个行为可以直接使用父类Beverage中的boilWater方法，其他方法都需要在Coffee子类中重写
Coffee.prototype.brew = function(){
    console.log('用开水冲咖啡')
}
Coffee.prototype.pourInCup = function(){
    console.log('咖啡倒进杯子里')
}
Coffee.prototype.addCondiments = function(){
    console.log('咖啡里面加点糖')
}

let coffee = new Coffee();
coffee.init();


let Tea = function(){}

Tea.prototype = new Beverage();

Tea.prototype.brew = function(){
    console.log("开水泡茶叶");
}
Tea.prototype.pourInCup = function(){
    console.log("茶叶水倒进杯子里");
}

Tea.prototype.addCondiments = function(){
    console.log("茶叶里面加点盐");
}

let tea = new Tea();
tea.init()